import pulp
import matplotlib.pyplot as plt
import pandas as pd
# 设置中文字体（以“SimSun 宋体”为例，其他如“Microsoft YaHei 微软雅黑”等也可）
plt.rcParams['font.sans-serif'] = ['SimSun']
# 解决负号显示为方块的问题（可选，避免特殊符号异常）
plt.rcParams['axes.unicode_minus'] = False

# 创建问题
model = pulp.LpProblem("Cargo_Loading_Optimization", pulp.LpMaximize)

# 参数定义
profits = [3100, 3800, 3500, 2850]  # 利润 p_i
volumes = [480, 650, 580, 390]     # 每吨体积 v_i

# 舱位限制（重量，体积）
weight_limits = [10, 16, 8]        # W1, W2, W3
volume_limits = [6800, 8700, 5300] # V1, V2, V3

# 决策变量 x[i][j] 表示货物i在舱位j的装载重量（吨）
x = [[pulp.LpVariable(f'x_{i+1}_{j+1}', lowBound=0) for j in range(3)] for i in range(4)]

# 目标函数：最大化总利润
model += pulp.lpSum(profits[i] * x[i][j] for i in range(4) for j in range(3))

# 每个舱的重量约束
for j in range(3):
    model += pulp.lpSum(x[i][j] for i in range(4)) <= weight_limits[j], f"Weight_Limit_Cargo_{j+1}"

# 每个舱的体积约束
for j in range(3):
    model += pulp.lpSum(x[i][j] * volumes[i] for i in range(4)) <= volume_limits[j], f"Volume_Limit_Cargo_{j+1}"

# 装载比例约束（为了平衡）
W1 = pulp.lpSum(x[i][0] for i in range(4))  # 前舱
W2 = pulp.lpSum(x[i][1] for i in range(4))  # 中舱
W3 = pulp.lpSum(x[i][2] for i in range(4))  # 后舱

model += 8 * W1 - 5 * W2 == 0, "Balance_Constraint_1"
model += 4 * W1 - 5 * W3 == 0, "Balance_Constraint_2"

# 求解
solver = pulp.PULP_CBC_CMD(msg=0)
result_status = model.solve(solver)

# 输出结果
print(f"求解状态: {pulp.LpStatus[model.status]}")
print(f"最大利润: {pulp.value(model.objective):,.2f} 元")
print("\n装载方案（单位：吨）:")

cargo_names = ['货物1', '货物2', '货物3', '货物4']
cargo_spaces = ['前舱', '中舱', '后舱']

for i in range(4):
    for j in range(3):
        val = x[i][j].varValue
        if val > 1e-5:  # 仅显示非零装载
            print(f"{cargo_names[i]} - {cargo_spaces[j]}: {val:.4f} 吨")

# 显示各舱实际载重
print("\n各舱总载重（吨）：")
print(f"前舱: {pulp.value(W1):.4f}, 中舱: {pulp.value(W2):.4f}, 后舱: {pulp.value(W3):.4f}")






# 创建 DataFrame 存储装载数据
data = []
for i in range(4):
    row = []
    for j in range(3):
        row.append(x[i][j].varValue if x[i][j].varValue is not None else 0)
    data.append(row)

df = pd.DataFrame(data,
                  index=['货物1', '货物2', '货物3', '货物4'],
                  columns=['前舱', '中舱', '后舱'])

# 转置：每列是一个货舱，行是货物
df_T = df.T

# 绘制堆叠柱状图
ax = df_T.plot(kind='bar', stacked=True, figsize=(8, 6), colormap='tab20')

plt.title("各货舱中货物装载情况（单位：吨）", fontsize=14)
plt.xlabel("货舱", fontsize=12)
plt.ylabel("装载重量（吨）", fontsize=12)
plt.xticks(rotation=0)
plt.legend(title='货物类型', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.tight_layout()

# 添加数值标签（吨数）
for bar_idx, container in enumerate(ax.containers):
    for rect in container:
        height = rect.get_height()
        if height > 0.05:  # 设置一个最小阈值避免小块太密集
            x = rect.get_x() + rect.get_width() / 2
            y = rect.get_y() + height / 2
            ax.text(x, y, f'{height:.2f}', ha='center', va='center', fontsize=9, color='white', weight='bold')

# 显示图形
plt.show()
